﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.UI.EM.Views.Interfaces;
using Common.Model;
using System.Data.Objects.DataClasses;
using Common.ServiceLogic;
using Microsoft.Practices.Composite.Presentation.Commands;
using System.ComponentModel;
using System.Windows;
using Microsoft.Practices.Composite.Events;

namespace Common.UI.EM.Views
{
    public partial class EntityPresentationModel<S, E, C, EV> : IEntityPresentationModel<S, E, C, EV>, INotifyPropertyChanged
        where S : IGenericEntityManagerServiceLogic<E, C, EV>, new()
        where E : IObjectWithChangeTracker, new()
        where C : CriteriaEntity
        where EV : ViewEntity
    {
        C _lastCriteria;
        public C LastCriteria
        {
            get { return _lastCriteria; }
            set { _lastCriteria = value; }
        }

        public EntityPresentationModel(IFilterView filterView, IListView listView, IDetailView detailView)
        {
            this.InitializeFilterPresentationModel(filterView);
            this.InitializeListPresentationModel(listView);
            this.InitializeDetailPresentationModel(detailView);
        }

        #region Filter

        public event SearchCalledEventHandler SearchCalled;

        public IFilterView FilterView
        {
            get;
            set;
        }

        public DelegateCommand<Object> SearchCommand
        {
            get;
            set;
        }

        C _criteriaEntity;
        public C CriteriaEntity
        {
            get { return _criteriaEntity; }
            set { _criteriaEntity = value; }
        }

        public void InitializeFilterPresentationModel(IFilterView view)
        {
            this.FilterView = view;
            this.FilterView.Model = this;

            this.AddFilterCommands();
        }

        private void AddFilterCommands()
        {
            this.SearchCommand = new DelegateCommand<object>(ExecuteSearch, CanExecuteSearch);
            this.AddFilterCustomCommands();
        }

        protected virtual void AddFilterCustomCommands()
        {

        }


        private void ExecuteSearch(Object arg)
        {
            if (this.ValidateFilter())
            {
                if (SearchCalled != null)
                {
                    SearchCalled(this, new DataEventArgs<CriteriaEntity>(this.CriteriaEntity));
                }

                this.LoadList(this.CriteriaEntity);
                LastCriteria = this.CriteriaEntity;
            }
        }

        private bool ValidateFilter()
        {
            return this.FilterView.Validate();
        }

        private Boolean CanExecuteSearch(Object arg)
        {
            return true;
        }


        public void LoadCriteria(C criteriaEntity)
        {
            CriteriaEntity = criteriaEntity;
        }

        #endregion

        #region List

        #region IListPresentationModel<S,E,C,EV> Members

        public event ViewCalledEventHandler ViewCalled;
        public event DeleteCalledEventHandler DeleteCalled;
        public event ModifyCalledEventHandler ModifyCalled;
        public event AddCalledEventHandler AddCalled;

        #endregion

        public ViewEntity SelectedEntity
        {
            get
            {
                return this.ListView.GetSelectedEntity();
            }
        }

        public virtual String DeleteLabel
        {
            get
            {
                return "Eliminar";
            }
        }

        public IListView ListView
        {
            get;
            set;
        }

        IGenericEntityManagerServiceLogic<E, C, EV> _entityManager;
        public IGenericEntityManagerServiceLogic<E, C, EV> EntityManager
        {
            get
            {
                if (_entityManager == null)
                {
                    _entityManager = new S();
                }
                return _entityManager;
            }
        }

        Object _list;
        public Object List
        {
            get
            {
                return _list;
            }
            set
            {
                _list = value;
                OnPropertyChanged("List");
            }
        }

        public DelegateCommand<Object> ViewCommand
        {
            get;
            set;
        }
        public DelegateCommand<Object> DeleteCommand
        {
            get;
            set;
        }
        public DelegateCommand<Object> ModifyCommand
        {
            get;
            set;
        }
        public DelegateCommand<Object> AddCommand
        {
            get;
            set;
        }

        public Boolean AllowAdd
        {
            get;
            set;
        }
        public Boolean AllowDelete
        {
            get;
            set;
        }
        public Boolean AllowModify
        {
            get;
            set;
        }
        public Boolean AllowView
        {
            get;
            set;
        }

        public void InitializeListPresentationModel(IListView view)
        {
            this.ListView = view;
            this.ListView.Model = this;

            this.AddListCommands();
        }

        private void AddListCommands()
        {
            this.ViewCommand = new DelegateCommand<object>(ExecuteView, CanExecuteView);
            this.DeleteCommand = new DelegateCommand<object>(ExecuteDelete, CanExecuteDelete);
            this.ModifyCommand = new DelegateCommand<object>(ExecuteModify, CanExecuteModify);
            this.AddCommand = new DelegateCommand<object>(ExecuteAdd, CanExecuteAdd);

            this.AddListCustomCommands();
        }

        protected virtual void AddListCustomCommands()
        {

        }

        protected void AddListCustomCommand(DelegateCommand<object> command, string text)
        {
            this.ListView.AddCustomCommand(command, text);
        }

        private void ExecuteView(Object arg)
        {
            if (this.SelectedEntity != null)
            {
                if (this.ViewCalled != null)
                {
                    this.ViewCalled(this, new Microsoft.Practices.Composite.Events.DataEventArgs<ViewEntity>(this.SelectedEntity));
                }
                this.ShowDetail(DetailMode.View, this.SelectedEntity);
            }
        }

        private Boolean CanExecuteView(Object arg)
        {
            return true;
        }


        private void ExecuteDelete(Object arg)
        {
            if (this.SelectedEntity != null && this.ValidateOnDelete())
            {
                this.DeleteEntity();

                if (this.DeleteCalled != null)
                {
                    this.DeleteCalled(this, new Microsoft.Practices.Composite.Events.DataEventArgs<ViewEntity>(this.SelectedEntity));
                }

                if (LastCriteria != null)
                {
                    this.LoadList(this.LastCriteria as C);
                }
            }
        }

        protected virtual bool ValidateOnDelete()
        {
            if (MessageBox.Show("¿Está seguro que desea eliminar permanentemente el registro?", "Confirmación", MessageBoxButton.YesNo) == MessageBoxResult.No)
            {
                return false;
            }
            return true;
        }

        protected virtual void DeleteEntity()
        {
            try
            {
                EntityManager.Delete(this.SelectedEntity);
            }
            catch (Exception ex)
            {
                if (ex.InnerException.Message.Contains("FK") && ex.InnerException.Message.Contains("DELETE"))
                {
                    MessageBox.Show("La entidad que está tratando de eliminar está relacionada con otras entidades. Elimine dichas relaciones y vuelva a intentarlo.");
                }
                else
                {
                    throw ex;
                }
            }
        }

        private Boolean CanExecuteDelete(Object arg)
        {
            return true;
        }


        private void ExecuteModify(Object arg)
        {
            if (this.SelectedEntity != null)
            {
                if (this.ModifyCalled != null)
                {
                    this.ModifyCalled(this, new Microsoft.Practices.Composite.Events.DataEventArgs<ViewEntity>(this.SelectedEntity));
                }

                this.ShowDetail(DetailMode.Modify, this.SelectedEntity);
            }
        }

        private Boolean CanExecuteModify(Object arg)
        {
            return true;
        }


        private void ExecuteAdd(Object arg)
        {
            if (this.AddCalled != null)
            {
                this.AddCalled(this, new EventArgs());
            }
            this.ShowDetail(DetailMode.Add, null);
        }

        private Boolean CanExecuteAdd(Object arg)
        {
            return true;
        }


        public void LoadList(C criteriaEntity)
        {
            List = EntityManager.Read(criteriaEntity);
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region IListPresentationModel<S,E,C,EV> Members

        public void AddColumnDefinition(String columnName, String header)
        {
            this.ListView.AddColumnDefinition(columnName, header);
        }

        #endregion


        public void ShowDetail(DetailMode detailMode, ViewEntity viewEntity)
        {
            if (detailMode != DetailMode.Add)
            {
                this.LoadEntity(viewEntity as EV);
            }
            else
            {
                this.LoadEntity(new E());
            }
            this.Mode = detailMode;
        }

        #endregion

        #region Detail


        #region IDetailPresentationModel<S,E,C,EV> Members

        public event CancelCalledEventHandler CancelCalled;
        public event SaveCalledEventHandler SaveCalled;

        #endregion

        E _entityObject;
        public E EntityObject
        {
            get { return _entityObject; }
            set
            {
                _entityObject = value;
                this.OnPropertyChanged("EntityObject");
            }
        }

        public IDetailView DetailView
        {
            get;
            set;
        }

        public DelegateCommand<Object> SaveCommand
        {
            get;
            set;
        }
        public DelegateCommand<Object> CancelCommand
        {
            get;
            set;
        }

        DetailMode _mode;
        public DetailMode Mode
        {
            get { return _mode; }
            set
            {
                _mode = value;
                OnPropertyChanged("Mode");
                this.RefreshMode();
            }
        }

        Boolean _isInAddMode;
        public Boolean IsInAddMode
        {
            get { return _isInAddMode; }
            set
            {
                _isInAddMode = value;
                OnPropertyChanged("IsInAddMode");
            }
        }
        Boolean _isInModifyMode;
        public Boolean IsInModifyMode
        {
            get { return _isInModifyMode; }
            set
            {
                _isInModifyMode = value;
                OnPropertyChanged("IsInModifyMode");
            }
        }
        Boolean _isInViewMode;
        public Boolean IsInViewMode
        {
            get { return _isInViewMode; }
            set
            {
                _isInViewMode = value;
                OnPropertyChanged("IsInViewMode");
            }
        }
        Boolean _isNotInViewMode;
        public Boolean IsNotInViewMode
        {
            get { return _isNotInViewMode; }
            set
            {
                _isNotInViewMode = value;
                OnPropertyChanged("IsNotInViewMode");
            }
        }

        private void RefreshMode()
        {
            this.IsInAddMode = Mode == DetailMode.Add;
            this.IsInModifyMode = Mode == DetailMode.Modify;
            this.IsInViewMode = Mode == DetailMode.View;
            IsNotInViewMode = Mode != DetailMode.View;
        }


        public void InitializeDetailPresentationModel(IDetailView view)
        {
            this.DetailView = view;
            this.DetailView.Model = this;
            this.AddDetailCommands();
        }

        private void AddDetailCommands()
        {
            this.SaveCommand = new DelegateCommand<object>(ExecuteSave, CanExecuteSave);
            this.CancelCommand = new DelegateCommand<object>(ExecuteCancel, CanExecuteCancel);

            this.AddDetailCustomCommands();
        }

        protected virtual void AddDetailCustomCommands()
        {
        }


        private void ExecuteSave(Object arg)
        {
            if (this.ValidateDetail())
            {
                try
                {

                    this.BeforeSave();

                    this.Save();

                    this.AfterSave();

                    if (SaveCalled != null)
                    {
                        SaveCalled(this, new EventArgs());
                    }

                    MessageBox.Show("Se ha guardado con éxito.", "CBE", MessageBoxButton.OK, MessageBoxImage.Information);

                    if (LastCriteria != null)
                    {
                        this.LoadList(this.LastCriteria as C);
                    }

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Error CBE", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }
        }

        protected virtual void BeforeSave()
        {
        }

        protected virtual void AfterSave()
        {
        }

        private void Save()
        {
            EntityManager.Save(this.EntityObject);
        }

        protected virtual Boolean ValidateDetail()
        {
            var rta = this.DetailView.Validate();
            if (!rta)
            {
                var str = new StringBuilder();
                foreach (var item in this.DetailView.ErrorMessages)
                {
                    str.AppendLine(item);
                }
                MessageBox.Show(str.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            return rta;
        }

        private Boolean CanExecuteSave(Object arg)
        {
            return true;
        }


        private void ExecuteCancel(Object arg)
        {
            EntityManager.RejectChanges();

            if (CancelCalled != null)
            {
                this.CancelCalled(this, new EventArgs());
            }
        }

        private Boolean CanExecuteCancel(Object arg)
        {
            return true;
        }


        public virtual void LoadEntity(Guid id)
        {
            LoadEntity(EntityManager.Read(id));
        }

        public void LoadEntity(E entityObject)
        {
            this.EntityObject = entityObject;
        }

        public void LoadEntity(EV ev)
        {
            this.EntityObject = EntityManager.Read(ev.ID);
        }

        #endregion

    }
}